<?php


namespace RedMVC\Db;

/**
 * Pdo class
 *
 * PDO Db class for multiple database types
 *
 * @category    RedMVC
 * @package     Db
 * @author      Jan Fischer, bitWorking <info@bitworking.de>
 */
class Pdo extends ADb{

    protected $sth;
    protected $dsn;

    public function connect($dsn, $dbusername = '', $dbpassword = ''){
        try{
            $this->dbh          = new \PDO($dsn, $dbusername, $dbpassword);
            $this->dsn          = $dsn;
            $this->dbusername   = $dbusername;
            $this->dbpassword   = $dbpassword;
        }
        catch(\PDOException $e){
            $this->printError($e->getMessage(), $e->getCode());
        }
        $this->setCharset();        
        $this->_setType($this->dbh->getAttribute(\PDO::ATTR_DRIVER_NAME));
        return $this->dbh;
    }
    
    public function setCharset($charset = 'utf8'){        
        $this->dbh->exec("SET CHARACTER SET ".$charset);
    }

    protected function printError($error, $errno = 0){
        throw new \Exception($error, $errno);        
	}

	public function quote($value){
        if(null === $value){
            return 'NULL';
        }
        return $this->dbh->quote($value);
	}

    public function query($query, array $args = array()){
        try{
            if(count($args) > 0){
                $query  = str_replace(array(" '%s' ", " '%d' ", ' %d '), ' ? ', $query);
            }
            $sth    = $this->dbh->prepare($query);
            $this->_lastQuery = $query;
            if(!$sth->execute($args)){
                $errorInfo = $sth->errorInfo();
                $this->printError($errorInfo[2], $errorInfo[1]);
            }
        }
        catch(\PDOException $e){            
            $this->printError($e->getMessage(), $e->getCode());
        }
        $this->sth = $sth;
        return $sth;
	}

    public function fetch($query, array $args = array()){
		$sth = $this->query($query, $args);
        return $sth->fetchAll(\PDO::FETCH_ASSOC);
    }
    
    public function fetchSelect($table, $valueField, $nameField, $selectSuffix = ''){
        $sth = $this->query("
            SELECT 
            $valueField AS valueField, 
            $nameField AS nameField
            FROM ".$table." $selectSuffix");
		$array = Array();
		$array[''] = 'Bitte auswählen';
        while($data = $sth->fetch(\PDO::FETCH_ASSOC)){
            $array[$data['valueField']] = $data['nameField'];
		}
		return $array;
    }
    
    public function insert($table, array $valueArray, $onDuplicateKeyValues = null){
        $values         = array_values($valueArray);        
        $keys           = array_keys($valueArray);
        $questionMarks  = array_fill(0, count($values), '?');
        $query  = "
            INSERT INTO `".$table."` (".implode(', ', $keys).") 
            VALUES (".implode(', ', $questionMarks).")
        ";
        $query .= $this->_onDuplicateKeyQuery($onDuplicateKeyValues);
        $result = $this->query($query, $values);
        return $this->insertId();
    }
    
    public function update($table, array $valueArray, $whereCondition = null){
        $query = "UPDATE `".$table."` SET ";
        // values
        $values = array();
        foreach($valueArray as $key=>$value){
            if(null === $value){
                $values[] = $key."=NULL";
            }
            else{
                $values[] = $key."=".$this->quote($value)."";
            }
        }
        $query .= implode(', ', $values);
        $query .= $this->_whereCondition($whereCondition);
        $result = $this->query($query);
        return $this->affectedRows();
    }
    
    public function delete($table, $whereCondition = null){
        $query = "DELETE FROM `".$table."`";
        $query .= $this->_whereCondition($whereCondition);
        $result = $this->query($query);
        return $this->affectedRows();
	}

    public function tableExists($table){
        $query  = "SELECT 1 FROM `".$table."` LIMIT 0";
        $result = $this->dbh->query($query);
        if (!$result){
            return false;
        }
        return true;
    }
    
    public function tableKeys($table){
        $result = $this->fetch("SELECT * FROM `".$table."` LIMIT 1");
        if(count($result)==0){return false;}
        return array_keys($result[0]);
    }
    
    public function tableFields($table){
        throw new \Exception('Pdo: not yet implemented');
    }
    
    public function count($query, array $args = array()){
        $query  = preg_replace('#SELECT\s.*?\sFROM#is', 'SELECT COUNT(*) FROM', $query, 1);
        $sth    = $this->query($query, $args);
        $result = $sth->fetchColumn();
        return $result;
    }
    
    public function insertId(){
	   return $this->dbh->lastInsertId();
	}
    
    public function affectedRows(){
        if(null === $this->sth){
            return 0;
        }
	    return $this->sth->rowCount();
	}
	
	public function beginTransaction(){
	   $this->dbh->beginTransaction();
	}
	
    public function commit(){
        $this->dbh->commit();
    }
    
    public function rollBack(){
        $this->dbh->rollBack();
    }
	
	public function close(){
		$this->dbh = null;
        $this->sth = null;
	}

    public function __deconstruct(){
        $this->close();
    }


}